package com.hup.joystick.view.quickMenu.setting;

import com.hup.joystick.constant.FunctionConstant.QuickMenuFunctionType;
import com.hup.joystick.model.QuickMenuConfig;
import com.hup.joystick.model.QuickMenuFunction;
import com.hup.joystick.view.customView.BaseMenuWindow;
import com.hup.joystick.view.quickMenu.QuickMenu;
import com.hup.joystick.view.quickMenu.setting.QMSAppItem.AppEditListener;
import com.hup.joystick.view.quickMenu.setting.QMSFunctionItem.FunctionEditListener;
import com.hup.utils.commons.ListUtil;
import com.hup.utils.commons.start.DialogHelper;
import com.hup.utils.commons.start.LookThemeUtil;
import com.hup.utils.commons.start.SpringContext;
import com.hup.utils.swing.ComponentUtil;
import com.hup.utils.swing.frame.BaseDialog;
import com.hup.utils.swing.frame.SingletonWindowHelper;
import lombok.extern.log4j.Log4j2;

import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;

/**
 * 本窗口是dialog,会阻塞其他window(目的是阻塞[功能配置],但造成MenuWindow也被阻塞了,所以需要一堆特殊处理)
 *
 * @author hugan
 * @date 2020/11/9
 */
@Log4j2
public class QuickMenuSettingDialog extends BaseDialog {
    public static final String TITLE = "快捷菜单配置";

    private final ViewItemEditHandler viewItemEditHandler = new ViewItemEditHandler();
    private final QuickMenuConfig config;
    private QuickMenuSettingForm form;
    /**
     * 是否修改过配置
     */
    private boolean configNotSave;

    public static void showFrame() {
        //显示本类阻塞窗口前,关闭其他MenuWindow
        BaseMenuWindow.disposeShowingWindows();
        QuickMenuSettingDialog window = SingletonWindowHelper.getWindow(QuickMenuSettingDialog.class);
        if (window == null) window = new QuickMenuSettingDialog();
        window.setVisible(true);
    }

    private QuickMenuSettingDialog() {
        super(TITLE);
        config = new QuickMenuConfig();

        initView();
        initListener();
        initModel();
    }

    private void initView() {
        form = new QuickMenuSettingForm();
        setContentPane(form.root);

        form.pFunction.setLayout(new GridLayout(1, 1));
        form.pApp.setLayout(new GridLayout(1, 1));
        ((QMSFunctionItem) form.pFunction.getComponent(0)).setEditListener(viewItemEditHandler);
        ((QMSAppItem) form.pApp.getComponent(0)).setEditListener(viewItemEditHandler);
        form.btnSave.setEnabled(false);

        LookThemeUtil.initFrameSize(this, 700, 450);
        setLocationRelativeTo(null);
    }

    private void initListener() {
        form.btnClear.addActionListener(confirm("清空配置", () -> {
            config.lstFunction.clear();
            config.lstApp.clear();
            viewItemEditHandler.initViewByConfig();
            switchConfigEdited(true);
        }));
        form.btnRestore.addActionListener(confirm("恢复默认功能", () -> {
            ArrayList<String> temp = new ArrayList<>(config.lstApp);
            config.toDefaultConfig();
            config.lstApp.addAll(temp);
            viewItemEditHandler.initViewByConfig();
            switchConfigEdited(true);
        }));
        form.btnPreview.addActionListener(e -> QuickMenu.showFrame(this, viewToConfig()));
        form.btnSave.addActionListener(e -> runWithCatch("保存配置", this::saveConfig));
        form.btnCancel.addActionListener(e -> {
            boolean close = onWindowClosing(null);
            if (close) dispose();
        });
    }

    private void initModel() {
        config.loadFromFile();
        viewItemEditHandler.initViewByConfig();
        boolean existsConfigFile = new File(config.configPath()).exists();
        switchConfigEdited(!existsConfigFile);
    }

    @Override
    public boolean onWindowClosing(WindowEvent e) {
        if (confirmNotSaveConfig()) return false;
        return super.onWindowClosing(e);
    }

    private void switchConfigEdited(boolean edited) {
        configNotSave = edited;
        form.btnSave.setEnabled(edited);
    }

    /**
     * 判断有无修改配置,如果有则弹窗确认
     *
     * @return true-取消进行中的操作(不放弃保存);false-放弃保存(然后取消已编辑状态)
     */
    private boolean confirmNotSaveConfig() {
        //没有配置或没有修改配置:不取消
        if (!configNotSave) return false;
        //不是确认取消:不取消
        boolean notSave = DialogHelper.yesNo("放弃保存?").show(this);
        if (notSave) switchConfigEdited(false);
        return !notSave;
    }

    private void saveConfig() {
        QuickMenuConfig temp = viewToConfig();
        config.lstFunction.clear();
        config.lstFunction.addAll(temp.lstFunction);
        config.lstApp.clear();
        config.lstApp.addAll(temp.lstApp);

        config.save();
        //重新加载一次
        viewItemEditHandler.initViewByConfig();
        switchConfigEdited(false);
        SpringContext.getBean(QuickMenu.class).notifyConfigUpdated();
    }

    private QuickMenuConfig viewToConfig() {
        QuickMenuConfig res = new QuickMenuConfig();
        for (int i = 0, count = form.pFunction.getComponentCount(); i < count; i++) {
            QMSFunctionItem item = (QMSFunctionItem) form.pFunction.getComponent(i);
            res.viewToFunction(item);
        }
        for (int i = 0, count = form.pApp.getComponentCount(); i < count; i++) {
            String path = ((QMSAppItem) form.pApp.getComponent(i)).getSelectedFilePath();
            if (path != null) res.lstApp.add(path);
        }
        return res;
    }

    private class ViewItemEditHandler implements FunctionEditListener, AppEditListener {
        /**
         * 过滤 {@link #initViewByConfig()}时,子控件触发的回调事件
         */
        private boolean itemEditing = false;

        @SuppressWarnings("DuplicatedCode")
        public void initViewByConfig() {
            log.info("");
            itemEditing = true;
            /*
            初始化列表:
            .先删除多余项目,再填充数据
            .界面item比config多1项
             */
            //功能
            int functionSize = config.lstFunction.size();
            ((GridLayout) form.pFunction.getLayout()).setRows(functionSize + 1);
            for (int i = form.pFunction.getComponentCount() - 1; i >= (functionSize + 1); i--) form.pFunction.remove(i);
            for (int i = 0; i < functionSize; i++) initFunctionItem(i, config.lstFunction.get(i));
            initFunctionItem(functionSize, null);

            //程序
            int appSize = config.lstApp.size();
            ((GridLayout) form.pApp.getLayout()).setRows(appSize + 1);
            for (int i = form.pApp.getComponentCount() - 1; i >= (appSize + 1); i--) form.pApp.remove(i);
            for (int i = 0; i < appSize; i++) initAppItem(i, config.lstApp.get(i));
            initAppItem(appSize, null);//最后一项是空的

            itemEditing = false;
        }

        private void initFunctionItem(int index, QuickMenuFunction function) {
            int count = form.pFunction.getComponentCount();
            log.debug("count={}, index={}", count, index);
            QMSFunctionItem item;
            if (index > count - 1) {
                item = new QMSFunctionItem();
                item.setEditListener(viewItemEditHandler);
                form.pFunction.add(item);
            } else {
                item = (QMSFunctionItem) form.pFunction.getComponent(index);
            }
            item.setFunction(function);
        }

        private void initAppItem(int index, String appPath) {
            int count = form.pApp.getComponentCount();
            log.debug("count={}, index={}", count, index);
            QMSAppItem item;
            if (index > count - 1) {
                item = new QMSAppItem();
                item.setEditListener(viewItemEditHandler);
                form.pApp.add(item);
            } else {
                item = (QMSAppItem) form.pApp.getComponent(index);
            }
            item.setApp(appPath);
        }

        @Override
        public void afterChangedType(QuickMenuFunctionType type) {
            if (itemEditing) {
                //log.info("itemEditing");
                return;
            }

            log.info("type={}", type);
            //保证只有最后一项是空白项
            boolean changedItem = false;
            if (type == QuickMenuFunctionType.NONE) {//删除多余空项
                for (int i = form.pFunction.getComponentCount() - 2; i >= 0; i--) {
                    QMSFunctionItem item = (QMSFunctionItem) form.pFunction.getComponent(i);
                    if (item.getType() == QuickMenuFunctionType.NONE) {
                        form.pFunction.remove(i);
                        changedItem = true;
                        break;
                    }
                }
            } else {//保证最后一项是空项
                int currentCount = form.pFunction.getComponentCount();
                QMSFunctionItem item = (QMSFunctionItem) form.pFunction.getComponent(currentCount - 1);
                if (item.getType() != QuickMenuFunctionType.NONE) {
                    initFunctionItem(currentCount, null);
                    changedItem = true;
                }
            }
            if (changedItem) {
                GridLayout layout = (GridLayout) form.pFunction.getLayout();
                layout.setRows(form.pFunction.getComponentCount());
                ComponentUtil.afterChangedChild(form.pFunction);
            }
            switchConfigEdited(true);
        }

        @Override
        public void afterChose(String chosePath) {
            if (itemEditing) {
                //log.info("itemEditing");
                return;
            }
            log.info("chosePath={}", chosePath);
            //保证只有最后一项是空白项
            boolean changedItem = false;
            if (chosePath == null) {//删除多余空项
                for (int i = form.pApp.getComponentCount() - 2; i >= 0; i--) {
                    QMSAppItem item = (QMSAppItem) form.pApp.getComponent(i);
                    if (item.getSelectedFilePath() == null) {
                        form.pApp.remove(i);
                        changedItem = true;
                        break;
                    }
                }
            } else {//保证最后一项是空项
                int currentCount = form.pApp.getComponentCount();
                QMSAppItem item = (QMSAppItem) form.pApp.getComponent(currentCount - 1);
                if (item.getSelectedFilePath() != null) {
                    initAppItem(currentCount, null);
                    changedItem = true;
                }
            }

            if (changedItem) {
                GridLayout layout = (GridLayout) form.pApp.getLayout();
                layout.setRows(form.pApp.getComponentCount());
                ComponentUtil.afterChangedChild(form.pApp);
            }
            switchConfigEdited(true);
        }

        @Override
        public void afterEditFunction() {
            if (itemEditing) {
                //log.info("itemEditing");
                return;
            }
            switchConfigEdited(true);
        }

        @Override
        public void onMove(QMSFunctionItem item, boolean isUp) {
            onMoveItem(item, isUp);
        }

        @Override
        public void onMove(QMSAppItem item, boolean isUp) {
            onMoveItem(item, isUp);
        }

        private void onMoveItem(Object item, boolean isUp) {
            boolean isFunction = item instanceof QMSFunctionItem;
            Container parent = isFunction ? form.pFunction : form.pApp;
            int componentCount = parent.getComponentCount();
            int index = parent.getComponentZOrder((Component) item);
            int indexOther;
            //最后一项不允许移动
            if (isUp && index > 0 && index <= componentCount - 2) {
                indexOther = index - 1;
            } else if (!isUp && index < componentCount - 2) {
                indexOther = index + 1;
            } else {
                log.debug("不能移动, isUp={}, index={}", isUp, index);
                return;
            }
            ArrayList<Component> items = ListUtil.asList(parent.getComponents());
            parent.removeAll();
            ListUtil.swap(items, index, indexOther);
            for (Component component : items) parent.add(component);
            ComponentUtil.afterChangedChild(parent);

            switchConfigEdited(true);
        }

    }

}
